// 每个新建的函数原型上都会有constructor
// 通过constructor来识别对象是否属于某个类，代码中关键字case后表达式均为函数

function typeAndValue(x) {
  if (x == null) return '' // null和undefined没有构造函数
  switch (x.constructor) {
    case Number:
      return 'number: ' + x
    case String:
      return 'string: ' + x
    case Date:
      return 'date: ' + x
    case RegExp:
      return 'regexp: ' +x
    case Function:
      return 'function: ' + x
    default:
      return 'object'
  }
}

console.log(typeAndValue(new Date()))

// 可以判断值的类型的type()函数
function type(o) {
  let t, c,n;
  // 另外一种特殊情形:NaN和它自身不相等
  if (o !== o) return 'nan'
  // 可以判断值的类型的type()函数
  if (o === null) return 'null'
  if ((t = classof(o)) !== 'object') return t
  return 'object'
}

function classof(o) {
    return Object.prototype.toString.call(o).slice(8, -1)
}
// 返回函数的名字(可能是空字符串），不是函数的话返回null
Function.prototype.getName = function () {
  if ('name' in this) return this.name
  return this.name = this.toString().match(/function\s*([^(]*)\(/)[1]
}

console.log(type(12))

// 将o的指定名字(或所有）的属性设置为不可写的和不可配置的
/**
 * Object.keys返回一个数组，包括对象自身的（不含继承的）所有可枚举属性（不含Symbol属性）。es5
 * Object.getOwnPropertyNames返回一个数组，包含对象自身的所有属性（不含Symbol属性，但是包括不可枚举属性）。es5
 * */
function freezeProps(o) {
  let props = (arguments.length === 1) ? Object.getOwnPropertyNames(o) : Array.prototype.slice.call(arguments, 1)
  props.forEach(function (n) { // //将它们都设置为只读的和不可变的
    //忽略不可配置的属性
    if (!Object.getOwnPropertyDescriptor(o, n).configurable) return
    Object.defineProperty(o, n, { configurable: false, writable: false })
  })
  return o
}
